package com.jwdemo
{
	import flash.display.BitmapData;
	import flash.external.ExternalInterface;
	import flash.geom.Matrix;
	
	public class TileMap
	{
		private var _mapdata:Array ;
		private var _resource:BitmapData ;
		private var _screenDim:Vector4 = new Vector4( 1024, 720 ) ;
		
		private var _screenDimX:int ;
		private var _screenDimY:int ;
		
		private var _tileDim:Object ;
		private var _tileWidth:int ;
		private var _tileHeight:int ;

		private var _mapWidth:int ;
		private var _mapHeight:int ;
		
		private var _pixelWidth:int ;
		private var _pixelHeight:int ;

		//private var _zeroPosTable:Array ;
		
		private var tilesDisplayWidth:int ;
		private var tilesDisplayHeight:int ;
		private var _tilesAcross:int ;
		private var _tilesDown: int ;
		
		
		private var vertices:Vector.<Number>;
		private var indices:Vector.<int>;
		private var uvData:Vector.<Number>;

		private var imgWidth:Number;
		private var imgHeight:Number;
		
		public function TileMap(mapdata:Array,tilemapResource:BitmapData,screenDim:Vector4 ,tileDim:Vector4)
		{
			
			this._mapdata 		=	mapdata ;
			
			
			this._resource		=	tilemapResource ;
			this._screenDim		=	screenDim  ;
			this._screenDimX	=	this._screenDim.X() ;
			this._screenDimY	=	this._screenDim.Y() ;
			
			this._tileWidth		=	tileDim ? tileDim.X() : 64 ;
			this._tileHeight	=	tileDim ? tileDim.Y() : this._tileWidth ;
			
			this._mapHeight		=	 this._mapdata.length ;
			this._mapWidth		=	 this._mapdata[0].length ;
			
			this._pixelWidth	=	this._mapWidth * this._tileWidth ;
			this._pixelHeight	=	this._mapHeight * this._tileHeight ;
			
			
			
			// calculate tiles needed to be rendered - round up to nearest tile.
			var tilesDisplayWidth:uint		= 	Math.ceil(this._screenDimX/this._tileWidth) ; 
			var tilesDisplayHeight:uint 	= 	Math.ceil(this._screenDimY/this._tileHeight) ;
			
			this.tilesDisplayWidth			=	tilesDisplayWidth ;
			this.tilesDisplayHeight			=	tilesDisplayHeight ;
			
			
		}



	public function GetMapIndex(x:uint, y:uint) : uint
	{
		return this._mapdata[y] ? this._mapdata[y][x] : 16;
		//return 66 ;
		
	}

	public function GetDimensions() : Object 
	{
		var pixelWidth:uint		=	this._pixelWidth ;
		var pixelHeight:uint	=	this._pixelHeight ;
		return {X: function():uint {return pixelWidth}, Y: function():uint {return pixelHeight}} ;
	}
	
	public function getDim() : Vector4 
	{
		return new Vector4(_pixelWidth, _pixelHeight )  ;
	}

	public function Render(rHelper:RenderHelper,tx:uint,ty:uint) : void
	{
		var newMapX:int					=	Math.floor(tx / this._tileWidth) ;
		var newMapY:int					=	Math.floor(ty / this._tileHeight) ;
		var fineX:int					=	tx % this._tileWidth ;
		var fineY:int					=	ty % this._tileHeight ;

		
		updateUVData(newMapX,newMapY,fineX,fineY) ;
		rHelper.renderTriangles(this._resource,vertices,indices,uvData,fineX,fineY)

	}

	
	// ideally we don't want to use finex,finey here - cos that'll mean
	// we only need to create the vertices vector table only once.
	// fine movement should only be done at the render stage... using matrix translation?
	
	private function updateUVData(mx:uint, my:uint, finex:int = 0, finey:int = 0):void {
		
		var j:int;
		var i:int;
		var imgX:Number = 0;
		var imgY:Number = 0 ;

		vertices=new Vector.<Number>();	// hopefully - we only need to define this once!
		indices=new Vector.<int>();		// wasteful - this only needs to built and defined once! 
		uvData=new Vector.<Number>();		

		
		imgY						=	-finey - 0;	 
		imgX						=	-finex - 0 ; // 128 - fudge start position of tile rendering

		var tilesetWidth:Number 	=	_resource.width;
		var tilesetHeight:Number 	=	_resource.height ;
		
		var tileWidth:Number		=	_tileWidth ;
		var tileHeight:Number		=	_tileHeight ;
		var numHFrames:Number		=	tilesetWidth/tileWidth ;
		

		var tilesDisplayWidth:uint	=	this.tilesDisplayWidth ;
		var tilesDisplayHeight:uint	=	this.tilesDisplayHeight ;
		var index:int 				= 	0 ;
		var vres:int 				=	tilesetWidth/(tileWidth) ;
		var hres:int 				=	tilesetHeight/(tileHeight) ;
		
		for (var x:uint = 0 ; x <= tilesDisplayWidth ; x++)
		{
			var xpos:uint = x + mx ;
			for (var y:uint = 0 ; y <= tilesDisplayHeight ; y++) 
			{
				var ypos:uint 			= 	y + my ;
				var tileNumber:uint 	=	this.GetMapIndex(xpos,ypos)
		
				j		=	int(tileNumber / numHFrames) ;
				i		=	(tileNumber % numHFrames) ;		
		
		

				// Screen Pos	***WASTEFUL! CAN MOVE THIS OUTSIDE THE LOOP AND DEFINED ONLY ONCE -IF I CAN DEFINE Pixel Postion Offsets WHEN
				// DRAWING TRIANGLES
				
				vertices.push(
				imgX+x*tileWidth,imgY+y*tileHeight,
				imgX+(x+1)*tileWidth,imgY+y*tileHeight,
				imgX+(x+1)*tileWidth,imgY+(y+1)*tileHeight,
				imgX+x*tileWidth,imgY+(y+1)*tileHeight);
		
				// uvPoints order - WASTEFUL! CAN BE MOVED OUT OF THIS LOOP AND CREATED ONLY ONCE!!!
				
				indices.push(index+0,index+1,index+3,index+1,index+2,index+3);
				index+=4 ;

		
				// particular tiledata - this is probably the only data that will change
				// every tileWidth, tileHeight pixel moves
				
				// Some adjustment here for rendering errors?
				// point the data 
				var px:Number = 2/tileWidth ;	// move this up and out!
				var py:Number = 2/tileHeight ;
				uvData.push((i+px)/vres,(j+py)/hres,(i+1-px)/vres,(j+py)/hres,(i+1-px)/vres,(j+1-py)/hres,(i+px)/vres,(j+1-py)/hres);
			}
		}
		
	}
		
 }
	
}
